home *** CD-ROM | disk | FTP | other *** search
/ Isometric Game Programming with DirectX 7.0 / Isometric Game Programming.iso / source / chapter18 / isohex18_3 / isohex18_3.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2000-09-11  |  25.1 KB  |  808 lines

  1. /*****************************************************************************
  2. IsoHex18_3.cpp
  3. Ernest S. Pazera
  4. 09SEPT2000
  5. Start a WIN32 Application Workspace, add in this file
  6. Requires the following libs:
  7. ddraw.lib, dxguid.lib
  8. Requires the following files:
  9. DDFuncs.h.cpp, GDICanvas.h/cpp, IsoMouseMap.h/cpp,
  10. IsoScroller.h/cpp, IsoTilePlotter.h/cpp, IsoTileWalker.h/cpp
  11. TileSet.h/cpp. IsoHexCore.h, IsoHexDefs.h
  12. IsoRenderer.h/cpp
  13. *****************************************************************************/
  14.  
  15. //////////////////////////////////////////////////////////////////////////////
  16. //INCLUDES
  17. //////////////////////////////////////////////////////////////////////////////
  18. #define WIN32_LEAN_AND_MEAN  
  19.  
  20. #include <windows.h>  
  21. #include "DDFuncs.h"
  22. #include "TileSet.h"
  23. #include "IsoHexCore.h"
  24. #include "IsoRenderer.h"
  25. #include <list>
  26.  
  27. //////////////////////////////////////////////////////////////////////////////
  28. //DEFINES
  29. //////////////////////////////////////////////////////////////////////////////
  30. //name for our window class
  31. #define WINDOWCLASS "ISOHEX18"
  32. //title of the application
  33. #define WINDOWTITLE "IsoHex 18-3"
  34.  
  35. const int MAPWIDTH=40;
  36. const int MAPHEIGHT=40;
  37.  
  38. //gamestates
  39. const int GS_IDLE=0;//waits for a keypress
  40. const int GS_STARTTURN=1;//starts a players turn
  41. const int GS_ENDTURN=2;//ends a players turn
  42. const int GS_NEXTUNIT=3;//finds the next unit to move
  43. const int GS_STARTMOVE=4;//starts moving the unit
  44. const int GS_DOMOVE=5;//moves the unit
  45. const int GS_ENDMOVE=6;//ends a unit move
  46. const int GS_NULLMOVE=7;//tells a unit to not move
  47. const int GS_SKIPMOVE=8;//temporarily skip the move
  48.  
  49. //////////////////////////////////////////////////////////////////////////////
  50. //TYPEDEFS/STRUCTS
  51. //////////////////////////////////////////////////////////////////////////////
  52. struct UnitInfo//unit information structure
  53. {
  54.     int iType;//type of unit
  55.     int iTeam;//team to which the unit belongs
  56.     POINT ptPosition;//map location of the unit
  57.     int iMovePoints;//number of movepoints left this turn
  58. };
  59.  
  60. typedef UnitInfo *PUNITINFO;//pointer type alias for unitinfo
  61.  
  62. typedef std::list<PUNITINFO> UNITLIST;//list of units
  63. typedef std::list<PUNITINFO>::iterator UNITLISTITER;//iterator for unit list
  64.  
  65. //////////////////////////////////////////////////////////////////////////////
  66. //PROTOTYPES
  67. //////////////////////////////////////////////////////////////////////////////
  68. bool Prog_Init();//game data initalizer
  69. void Prog_Loop();//main game loop
  70. void Prog_Done();//game clean up
  71.  
  72. //////////////////////////////////////////////////////////////////////////////
  73. //GLOBALS
  74. //////////////////////////////////////////////////////////////////////////////
  75. HINSTANCE hInstMain=NULL;//main application handle
  76. HWND hWndMain=NULL;//handle to our main window
  77.  
  78. //game state
  79. int iGameState=GS_IDLE;
  80. int iCurrentTeam=0;//the team whose turn it currently is
  81.  
  82. //directdraw
  83. LPDIRECTDRAW7 lpdd=NULL;
  84. LPDIRECTDRAWSURFACE7 lpddsMain=NULL;
  85. LPDIRECTDRAWSURFACE7 lpddsBack=NULL;
  86. LPDIRECTDRAWSURFACE7 lpddsFrame=NULL;
  87.  
  88. //tilesets
  89. CTileSet tsBack;//background
  90. CTileSet tsUnit;//unit
  91. CTileSet tsShield;//shields
  92.  
  93. //offsets for the shields
  94. POINT ptShieldOffset[2];//one for each unit
  95.  
  96. //isohexcore components
  97. CTilePlotter TilePlotter;//plotter
  98. CTileWalker TileWalker;//walker
  99. CScroller Scroller;//scroller
  100. CMouseMap MouseMap;//mousemap
  101. CRenderer Renderer;//renderer
  102.  
  103. POINT ptScroll;//keep track of how quickly we scroll
  104.  
  105. //map location structure
  106. struct MapLocation
  107. {
  108.     UNITLIST ulUnitList;//list of units on this map location
  109. };
  110.  
  111. MapLocation mlMap[MAPWIDTH][MAPHEIGHT];//map array
  112. UNITLIST MainUnitList;//unit list for all units
  113. UNITLIST TeamUnitList;//unit list for teams(Current Players Turn)
  114. PUNITINFO pCurrentUnit;//current unit being moved
  115. bool bFlash;//controls the flashing of the current unit
  116. ISODIRECTION idMoveUnit;//direction in which the unit will be moved
  117.  
  118. //rendering functionprototype
  119. void RenderFunc(LPDIRECTDRAWSURFACE7 lpddsDst,RECT* rcClip,int xDst,int yDst,int xMap,int yMap);
  120.  
  121. //////////////////////////////////////////////////////////////////////////////
  122. //WINDOWPROC
  123. //////////////////////////////////////////////////////////////////////////////
  124. LRESULT CALLBACK TheWindowProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
  125. {
  126.     //which message did we get?
  127.     switch(uMsg)
  128.     {
  129.     case WM_KEYDOWN:
  130.         {
  131.             switch(wParam)
  132.             {
  133.             case VK_ESCAPE:
  134.                 {
  135.                     DestroyWindow(hWndMain);
  136.                     return(0);
  137.                 }break;
  138.             case VK_SPACE://do not move unit
  139.                 {
  140.                     if(iGameState==GS_IDLE) iGameState=GS_NULLMOVE;//only respond when gamestate is GS_IDLE;
  141.                     return(0);
  142.                 }break;
  143.             case 'W'://wait to move this unit later
  144.                 {
  145.                     if(iGameState==GS_IDLE) iGameState=GS_SKIPMOVE;//skip this unit for now
  146.                 }break;
  147.             case VK_NUMPAD8:
  148.             case VK_UP:
  149.                 {
  150.                     if(iGameState==GS_IDLE)//gamestate must be GS_IDLE
  151.                     {
  152.                         idMoveUnit=ISO_NORTH;//move to the north
  153.                         POINT ptNext=TileWalker.TileWalk(pCurrentUnit->ptPosition,idMoveUnit);//check the next position
  154.                         if(ptNext.x>=0 && ptNext.y>=0 && ptNext.x<MAPWIDTH && ptNext.y<MAPWIDTH)//bounds checking
  155.                         {
  156.                             if(mlMap[ptNext.x][ptNext.y].ulUnitList.empty())//if the map location is empty
  157.                             {
  158.                                 iGameState=GS_STARTMOVE;//set the unit in motion
  159.                             }
  160.                             else
  161.                             {
  162.                                 UNITLISTITER iter=mlMap[ptNext.x][ptNext.y].ulUnitList.begin();//get the first entry in the list
  163.                                 PUNITINFO pUnitInfo=*iter;//get the unit from the list
  164.                                 if(pUnitInfo->iTeam==pCurrentUnit->iTeam)//must be the same team
  165.                                 {
  166.                                     iGameState=GS_STARTMOVE;
  167.                                 }
  168.                             }
  169.                         }
  170.                     }
  171.                 }break;
  172.             case VK_NUMPAD9:
  173.             case VK_PRIOR:
  174.                 {
  175.                     if(iGameState==GS_IDLE)//gamestate must be GS_IDLE
  176.                     {
  177.                         idMoveUnit=ISO_NORTHEAST;//move to the north
  178.                         POINT ptNext=TileWalker.TileWalk(pCurrentUnit->ptPosition,idMoveUnit);//check the next position
  179.                         if(ptNext.x>=0 && ptNext.y>=0 && ptNext.x<MAPWIDTH && ptNext.y<MAPWIDTH)//bounds checking
  180.                         {
  181.                             if(mlMap[ptNext.x][ptNext.y].ulUnitList.empty())//if the map location is empty
  182.                             {
  183.                                 iGameState=GS_STARTMOVE;//set the unit in motion
  184.                             }
  185.                             else
  186.                             {
  187.                                 UNITLISTITER iter=mlMap[ptNext.x][ptNext.y].ulUnitList.begin();//get the first entry in the list
  188.                                 PUNITINFO pUnitInfo=*iter;//get the unit from the list
  189.                                 if(pUnitInfo->iTeam==pCurrentUnit->iTeam)//must be the same team
  190.                                 {
  191.                                     iGameState=GS_STARTMOVE;
  192.                                 }
  193.                             }
  194.                         }
  195.                     }
  196.                 }break;
  197.             case VK_NUMPAD6:
  198.             case VK_RIGHT:
  199.                 {
  200.                     if(iGameState==GS_IDLE)//gamestate must be GS_IDLE
  201.                     {
  202.                         idMoveUnit=ISO_EAST;//move to the north
  203.                         POINT ptNext=TileWalker.TileWalk(pCurrentUnit->ptPosition,idMoveUnit);//check the next position
  204.                         if(ptNext.x>=0 && ptNext.y>=0 && ptNext.x<MAPWIDTH && ptNext.y<MAPWIDTH)//bounds checking
  205.                         {
  206.                             if(mlMap[ptNext.x][ptNext.y].ulUnitList.empty())//if the map location is empty
  207.                             {
  208.                                 iGameState=GS_STARTMOVE;//set the unit in motion
  209.                             }
  210.                             else
  211.                             {
  212.                                 UNITLISTITER iter=mlMap[ptNext.x][ptNext.y].ulUnitList.begin();//get the first entry in the list
  213.                                 PUNITINFO pUnitInfo=*iter;//get the unit from the list
  214.                                 if(pUnitInfo->iTeam==pCurrentUnit->iTeam)//must be the same team
  215.                                 {
  216.                                     iGameState=GS_STARTMOVE;
  217.                                 }
  218.                             }
  219.                         }
  220.                     }
  221.                 }break;
  222.             case VK_NUMPAD3:
  223.             case VK_NEXT:
  224.                 {
  225.                     if(iGameState==GS_IDLE)//gamestate must be GS_IDLE
  226.                     {
  227.                         idMoveUnit=ISO_SOUTHEAST;//move to the north
  228.                         POINT ptNext=TileWalker.TileWalk(pCurrentUnit->ptPosition,idMoveUnit);//check the next position
  229.                         if(ptNext.x>=0 && ptNext.y>=0 && ptNext.x<MAPWIDTH && ptNext.y<MAPWIDTH)//bounds checking
  230.                         {
  231.                             if(mlMap[ptNext.x][ptNext.y].ulUnitList.empty())//if the map location is empty
  232.                             {
  233.                                 iGameState=GS_STARTMOVE;//set the unit in motion
  234.                             }
  235.                             else
  236.                             {
  237.                                 UNITLISTITER iter=mlMap[ptNext.x][ptNext.y].ulUnitList.begin();//get the first entry in the list
  238.                                 PUNITINFO pUnitInfo=*iter;//get the unit from the list
  239.                                 if(pUnitInfo->iTeam==pCurrentUnit->iTeam)//must be the same team
  240.                                 {
  241.                                     iGameState=GS_STARTMOVE;
  242.                                 }
  243.                             }
  244.                         }
  245.                     }
  246.                 }break;
  247.             case VK_NUMPAD2:
  248.             case VK_DOWN:
  249.                 {
  250.                     if(iGameState==GS_IDLE)//gamestate must be GS_IDLE
  251.                     {
  252.                         idMoveUnit=ISO_SOUTH;//move to the north
  253.                         POINT ptNext=TileWalker.TileWalk(pCurrentUnit->ptPosition,idMoveUnit);//check the next position
  254.                         if(ptNext.x>=0 && ptNext.y>=0 && ptNext.x<MAPWIDTH && ptNext.y<MAPWIDTH)//bounds checking
  255.                         {
  256.                             if(mlMap[ptNext.x][ptNext.y].ulUnitList.empty())//if the map location is empty
  257.                             {
  258.                                 iGameState=GS_STARTMOVE;//set the unit in motion
  259.                             }
  260.                             else
  261.                             {
  262.                                 UNITLISTITER iter=mlMap[ptNext.x][ptNext.y].ulUnitList.begin();//get the first entry in the list
  263.                                 PUNITINFO pUnitInfo=*iter;//get the unit from the list
  264.                                 if(pUnitInfo->iTeam==pCurrentUnit->iTeam)//must be the same team
  265.                                 {
  266.                                     iGameState=GS_STARTMOVE;
  267.                                 }
  268.                             }
  269.                         }
  270.                     }
  271.                 }break;
  272.             case VK_NUMPAD1:
  273.             case VK_END:
  274.                 {
  275.                     if(iGameState==GS_IDLE)//gamestate must be GS_IDLE
  276.                     {
  277.                         idMoveUnit=ISO_SOUTHWEST;//move to the north
  278.                         POINT ptNext=TileWalker.TileWalk(pCurrentUnit->ptPosition,idMoveUnit);//check the next position
  279.                         if(ptNext.x>=0 && ptNext.y>=0 && ptNext.x<MAPWIDTH && ptNext.y<MAPWIDTH)//bounds checking
  280.                         {
  281.                             if(mlMap[ptNext.x][ptNext.y].ulUnitList.empty())//if the map location is empty
  282.                             {
  283.                                 iGameState=GS_STARTMOVE;//set the unit in motion
  284.                             }
  285.                             else
  286.                             {
  287.                                 UNITLISTITER iter=mlMap[ptNext.x][ptNext.y].ulUnitList.begin();//get the first entry in the list
  288.                                 PUNITINFO pUnitInfo=*iter;//get the unit from the list
  289.                                 if(pUnitInfo->iTeam==pCurrentUnit->iTeam)//must be the same team
  290.                                 {
  291.                                     iGameState=GS_STARTMOVE;
  292.                                 }
  293.                             }
  294.                         }
  295.                     }
  296.                 }break;
  297.             case VK_NUMPAD4:
  298.             case VK_LEFT:
  299.                 {
  300.                     if(iGameState==GS_IDLE)//gamestate must be GS_IDLE
  301.                     {
  302.                         idMoveUnit=ISO_WEST;//move to the north
  303.                         POINT ptNext=TileWalker.TileWalk(pCurrentUnit->ptPosition,idMoveUnit);//check the next position
  304.                         if(ptNext.x>=0 && ptNext.y>=0 && ptNext.x<MAPWIDTH && ptNext.y<MAPWIDTH)//bounds checking
  305.                         {
  306.                             if(mlMap[ptNext.x][ptNext.y].ulUnitList.empty())//if the map location is empty
  307.                             {
  308.                                 iGameState=GS_STARTMOVE;//set the unit in motion
  309.                             }
  310.                             else
  311.                             {
  312.                                 UNITLISTITER iter=mlMap[ptNext.x][ptNext.y].ulUnitList.begin();//get the first entry in the list
  313.                                 PUNITINFO pUnitInfo=*iter;//get the unit from the list
  314.                                 if(pUnitInfo->iTeam==pCurrentUnit->iTeam)//must be the same team
  315.                                 {
  316.                                     iGameState=GS_STARTMOVE;
  317.                                 }
  318.                             }
  319.                         }
  320.                     }
  321.                 }break;
  322.             case VK_NUMPAD7:
  323.             case VK_HOME:
  324.                 {
  325.                     if(iGameState==GS_IDLE)//gamestate must be GS_IDLE
  326.                     {
  327.                         idMoveUnit=ISO_NORTHWEST;//move to the north
  328.                         POINT ptNext=TileWalker.TileWalk(pCurrentUnit->ptPosition,idMoveUnit);//check the next position
  329.                         if(ptNext.x>=0 && ptNext.y>=0 && ptNext.x<MAPWIDTH && ptNext.y<MAPWIDTH)//bounds checking
  330.                         {
  331.                             if(mlMap[ptNext.x][ptNext.y].ulUnitList.empty())//if the map location is empty
  332.                             {
  333.                                 iGameState=GS_STARTMOVE;//set the unit in motion
  334.                             }
  335.                             else
  336.                             {
  337.                                 UNITLISTITER iter=mlMap[ptNext.x][ptNext.y].ulUnitList.begin();//get the first entry in the list
  338.                                 PUNITINFO pUnitInfo=*iter;//get the unit from the list
  339.                                 if(pUnitInfo->iTeam==pCurrentUnit->iTeam)//must be the same team
  340.                                 {
  341.                                     iGameState=GS_STARTMOVE;
  342.                                 }
  343.                             }
  344.                         }
  345.                     }
  346.                 }break;
  347.             }
  348.         }break;
  349.     case WM_DESTROY://the window is being destroyed
  350.         {
  351.  
  352.             //tell the application we are quitting
  353.             PostQuitMessage(0);
  354.  
  355.             //handled message, so return 0
  356.             return(0);
  357.  
  358.         }break;
  359.     case WM_PAINT://the window needs repainting
  360.         {
  361.             //a variable needed for painting information
  362.             PAINTSTRUCT ps;
  363.             
  364.             //start painting
  365.             HDC hdc=BeginPaint(hwnd,&ps);
  366.  
  367.             /////////////////////////////
  368.             //painting code would go here
  369.             /////////////////////////////
  370.  
  371.             //end painting
  372.             EndPaint(hwnd,&ps);
  373.                         
  374.             //handled message, so return 0
  375.             return(0);
  376.         }break;
  377.     }
  378.  
  379.     //pass along any other message to default message handler
  380.     return(DefWindowProc(hwnd,uMsg,wParam,lParam));
  381. }
  382.  
  383.  
  384. //////////////////////////////////////////////////////////////////////////////
  385. //WINMAIN
  386. //////////////////////////////////////////////////////////////////////////////
  387. int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd)
  388. {
  389.     //assign instance to global variable
  390.     hInstMain=hInstance;
  391.  
  392.     //create window class
  393.     WNDCLASSEX wcx;
  394.  
  395.     //set the size of the structure
  396.     wcx.cbSize=sizeof(WNDCLASSEX);
  397.  
  398.     //class style
  399.     wcx.style=CS_OWNDC | CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
  400.  
  401.     //window procedure
  402.     wcx.lpfnWndProc=TheWindowProc;
  403.  
  404.     //class extra
  405.     wcx.cbClsExtra=0;
  406.  
  407.     //window extra
  408.     wcx.cbWndExtra=0;
  409.  
  410.     //application handle
  411.     wcx.hInstance=hInstMain;
  412.  
  413.     //icon
  414.     wcx.hIcon=LoadIcon(NULL,IDI_APPLICATION);
  415.  
  416.     //cursor
  417.     wcx.hCursor=LoadCursor(NULL,IDC_ARROW);
  418.  
  419.     //background color
  420.     wcx.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH);
  421.  
  422.     //menu
  423.     wcx.lpszMenuName=NULL;
  424.  
  425.     //class name
  426.     wcx.lpszClassName=WINDOWCLASS;
  427.  
  428.     //small icon
  429.     wcx.hIconSm=NULL;
  430.  
  431.     //register the window class, return 0 if not successful
  432.     if(!RegisterClassEx(&wcx)) return(0);
  433.  
  434.     //create main window
  435.     hWndMain=CreateWindowEx(0,WINDOWCLASS,WINDOWTITLE, WS_POPUP | WS_VISIBLE,0,0,320,240,NULL,NULL,hInstMain,NULL);
  436.  
  437.     //error check
  438.     if(!hWndMain) return(0);
  439.  
  440.     //if program initialization failed, then return with 0
  441.     if(!Prog_Init()) return(0);
  442.  
  443.     //message structure
  444.     MSG msg;
  445.  
  446.     //message pump
  447.     for(;;)    
  448.     {
  449.         //look for a message
  450.         if(PeekMessage(&msg,NULL,0,0,PM_REMOVE))
  451.         {
  452.             //there is a message
  453.  
  454.             //check that we arent quitting
  455.             if(msg.message==WM_QUIT) break;
  456.             
  457.             //translate message
  458.             TranslateMessage(&msg);
  459.  
  460.             //dispatch message
  461.             DispatchMessage(&msg);
  462.         }
  463.  
  464.         //run main game loop
  465.         Prog_Loop();
  466.     }
  467.     
  468.     //clean up program data
  469.     Prog_Done();
  470.  
  471.     //return the wparam from the WM_QUIT message
  472.     return(msg.wParam);
  473. }
  474.  
  475. //////////////////////////////////////////////////////////////////////////////
  476. //INITIALIZATION
  477. //////////////////////////////////////////////////////////////////////////////
  478. bool Prog_Init()
  479. {
  480.     //create IDirectDraw object
  481.     lpdd=LPDD_Create(hWndMain,DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_ALLOWREBOOT);
  482.  
  483.     //set display mode
  484.     lpdd->SetDisplayMode(640,480,16,0,0);
  485.  
  486.     //create primary surface
  487.     lpddsMain=LPDDS_CreatePrimary(lpdd,1);
  488.  
  489.     //get back buffer
  490.     lpddsBack=LPDDS_GetSecondary(lpddsMain);
  491.  
  492.     //create the frame buffer
  493.     lpddsFrame=LPDDS_CreateOffscreen(lpdd,640,480);
  494.  
  495.     //load in the mousemap
  496.     MouseMap.Load("MouseMap.bmp");
  497.  
  498.     //set up the tile plotter
  499.     TilePlotter.SetMapType(ISOMAP_DIAMOND);//diamond mode
  500.     TilePlotter.SetTileSize(MouseMap.GetWidth(),MouseMap.GetHeight());//grab width and height from mousemap
  501.  
  502.     //set up tile walker to diamond mode
  503.     TileWalker.SetMapType(ISOMAP_DIAMOND);
  504.  
  505.     //set up screeen space
  506.     RECT rcTemp;
  507.     SetRect(&rcTemp,0,0,640,480);
  508.     Scroller.SetScreenSpace(&rcTemp);
  509.  
  510.     //load in tiles and cursor
  511.     tsBack.Load(lpdd,"backgroundts.bmp");
  512.     tsUnit.Load(lpdd,"units.bmp");
  513.     tsShield.Load(lpdd,"shields.bmp");
  514.  
  515.     //calculate the shield offsets
  516.     ptShieldOffset[0].x=tsUnit.GetTileList()[0].rcSrc.right-tsUnit.GetTileList()[0].ptAnchor.x;
  517.     ptShieldOffset[0].y=tsUnit.GetTileList()[0].rcSrc.top-tsUnit.GetTileList()[0].ptAnchor.y;
  518.     ptShieldOffset[1].x=tsUnit.GetTileList()[1].rcSrc.right-tsUnit.GetTileList()[1].ptAnchor.x;
  519.     ptShieldOffset[1].y=tsUnit.GetTileList()[1].rcSrc.top-tsUnit.GetTileList()[1].ptAnchor.y;
  520.  
  521.     //grab tile extent from tileset
  522.     CopyRect(&rcTemp,&tsBack.GetTileList()[0].rcDstExt);
  523.  
  524.     //calculate the worldspace
  525.     Scroller.CalcWorldSpace(&TilePlotter,&rcTemp,MAPWIDTH,MAPHEIGHT);
  526.  
  527.     //calculate the mousemap reference point
  528.     MouseMap.CalcReferencePoint(&TilePlotter,&rcTemp);
  529.  
  530.     //calculate anchor space
  531.     Scroller.CalcAnchorSpace();
  532.  
  533.     //set wrap modes for scroller
  534.     Scroller.SetHWrapMode(WRAPMODE_CLIP);
  535.     Scroller.SetVWrapMode(WRAPMODE_CLIP);
  536.  
  537.     //set scroller anchor to (0,0)
  538.     Scroller.GetAnchor()->x=0;
  539.     Scroller.GetAnchor()->y=0;
  540.  
  541.     //attach scrolelr and tilewalker to mousemap
  542.     MouseMap.SetScroller(&Scroller);
  543.     MouseMap.SetTileWalker(&TileWalker);
  544.  
  545.     //set up the map to a random tilefield
  546.     int x;
  547.     int y;
  548.     for(x=0;x<MAPWIDTH;x++)
  549.     {
  550.         for(y=0;y<MAPHEIGHT;y++)
  551.         {
  552.             mlMap[x][y].ulUnitList.clear();//clear out the list for this map location
  553.         }
  554.     }
  555.  
  556.     //place the units
  557.     int team;
  558.     int count;
  559.     PUNITINFO pUnitInfo;
  560.     POINT ptTest;
  561.     for(team=0;team<2;team++)//place units for both teams
  562.     {
  563.         for(count=0;count<20;count++)//place 20 units for each team
  564.         {
  565.             //check for a valid placement
  566.             bool found=false;
  567.             while(!found)
  568.             {
  569.                 //random placement
  570.                 ptTest.x=rand()%MAPWIDTH;
  571.                 ptTest.y=rand()%MAPHEIGHT;
  572.                 //check for a unit at that position
  573.                 if(mlMap[ptTest.x][ptTest.y].ulUnitList.empty())
  574.                 {
  575.                     //unit list at location is empty... you can place the unit
  576.                     found=true;
  577.                 }
  578.                 else
  579.                 {
  580.                     //unit list is not empty, so must be occupied by the same team to be a valid location
  581.                     UNITLISTITER iter=mlMap[ptTest.x][ptTest.y].ulUnitList.begin();//get iterator to beginning of list
  582.                     pUnitInfo=*iter;//grab the items stored
  583.                     //check for the same team
  584.                     if(pUnitInfo->iTeam==team)
  585.                     {
  586.                         //same team, valid location
  587.                         found=true;
  588.                     }
  589.  
  590.                 }
  591.             }
  592.             //create the unit
  593.             pUnitInfo=new UnitInfo;
  594.             pUnitInfo->iTeam=team;//team
  595.             pUnitInfo->iType=rand()%2;//type
  596.             pUnitInfo->ptPosition=ptTest;//location
  597.             //place unit in the main list
  598.             MainUnitList.push_back(pUnitInfo);
  599.             //place unit on the map
  600.             mlMap[pUnitInfo->ptPosition.x][pUnitInfo->ptPosition.y].ulUnitList.push_back(pUnitInfo);
  601.         }
  602.     }
  603.  
  604.     //calculate the extent rect
  605.     RECT rcExtent;
  606.     CopyRect(&rcExtent,&tsBack.GetTileList()[0].rcDstExt);//set to background extent
  607.     UnionRect(&rcExtent,&rcExtent,&tsUnit.GetTileList()[0].rcDstExt);//union with unit extent
  608.     rcExtent.right+=tsShield.GetTileList()[0].rcDstExt.right;//adjust the extent for the width of the shield
  609.  
  610.     //set up the renderer
  611.     Renderer.SetBackBuffer(lpddsBack);
  612.     Renderer.SetExtentRect(&rcExtent);
  613.     Renderer.SetFrameBuffer(lpddsFrame);
  614.     Renderer.SetMapSize(MAPWIDTH,MAPHEIGHT);
  615.     Renderer.SetMouseMap(&MouseMap);
  616.     Renderer.SetPlotter(&TilePlotter);
  617.     Renderer.SetRenderFunction(RenderFunc);
  618.     Renderer.SetScroller(&Scroller);
  619.     Renderer.SetUpdateRectCount(100);
  620.     Renderer.SetWalker(&TileWalker);
  621.  
  622.     //set the initial gamestate
  623.     iGameState=GS_STARTTURN;
  624.     iCurrentTeam=0;//current team
  625.     TeamUnitList.clear();//clear out the team's unit list
  626.  
  627.     //update the entire screenspace
  628.     Renderer.AddRect(Scroller.GetScreenSpace());
  629.  
  630.     return(true);//return success
  631. }
  632.  
  633. //////////////////////////////////////////////////////////////////////////////
  634. //CLEANUP
  635. //////////////////////////////////////////////////////////////////////////////
  636. void Prog_Done()
  637. {
  638.     //release frame buffer
  639.     LPDDS_Release(&lpddsFrame);
  640.  
  641.     //release main/back surfaces
  642.     LPDDS_Release(&lpddsMain);
  643.  
  644.     //release directdraw
  645.     LPDD_Release(&lpdd);
  646. }
  647.  
  648. //////////////////////////////////////////////////////////////////////////////
  649. //MAIN GAME LOOP
  650. //////////////////////////////////////////////////////////////////////////////
  651. void Prog_Loop()
  652. {
  653.     switch(iGameState)
  654.     {
  655.     case GS_STARTTURN://start the current team's turn
  656.         {
  657.             PUNITINFO pUnitInfo;//variable to check for the team's units
  658.             UNITLISTITER iter;//iterator for the main unit list
  659.             for(iter=MainUnitList.begin();iter!=MainUnitList.end();iter++)//iterate through the main unit list
  660.             {
  661.                 pUnitInfo=*iter;//grab the unit from the list
  662.                 if(pUnitInfo->iTeam==iCurrentTeam)//does this unit belong to the current team?
  663.                 {
  664.                     //add this unit to the team list
  665.                     TeamUnitList.push_back(pUnitInfo);
  666.                 }
  667.             }
  668.             //set the next gamestate
  669.             iGameState=GS_NEXTUNIT;
  670.         }break;
  671.     case GS_NEXTUNIT://select the next unit as the current unit
  672.         {
  673.             //set current unit to NULL
  674.             pCurrentUnit=NULL;
  675.             if(TeamUnitList.empty())//if the team unit list is empty
  676.             {
  677.                 iGameState=GS_ENDTURN;//end the turn
  678.             }
  679.             else
  680.             {
  681.                 //turn is not over
  682.                 UNITLISTITER iter=TeamUnitList.begin();//get the first unit in the team list
  683.                 pCurrentUnit=*iter;//grab the unit from the list
  684.                 TeamUnitList.pop_front();//remove the unit from the list
  685.  
  686.                 mlMap[pCurrentUnit->ptPosition.x][pCurrentUnit->ptPosition.y].ulUnitList.remove(pCurrentUnit);//remove the unit from the map location
  687.                 mlMap[pCurrentUnit->ptPosition.x][pCurrentUnit->ptPosition.y].ulUnitList.push_front(pCurrentUnit);//place unit at the top of the map locations unit list
  688.  
  689.                 POINT ptPlot=TilePlotter.PlotTile(pCurrentUnit->ptPosition);//plot the unit's location
  690.                 POINT ptScreen=Scroller.WorldToScreen(ptPlot);//translate into screen coordinates
  691.  
  692.                 if(!PtInRect(Scroller.GetScreenSpace(),ptScreen))//check to see if point is within screenspace
  693.                 {
  694.                     //not on screen
  695.                     ptPlot.x-=(Scroller.GetScreenSpaceWidth()/2);
  696.                     ptPlot.y-=(Scroller.GetAnchorSpaceHeight()/2);
  697.                     //set the anchor
  698.                     Scroller.SetAnchor(&ptPlot);
  699.                     Renderer.AddRect(Scroller.GetScreenSpace());
  700.                 }
  701.                 iGameState=GS_IDLE;//set to idling gamestate
  702.             }
  703.         }break;
  704.     case GS_ENDTURN://end of a player's turn
  705.         {
  706.             //clear out team unit list(just to be sure)
  707.             TeamUnitList.clear();
  708.  
  709.             //change team
  710.             iCurrentTeam=1-iCurrentTeam;
  711.  
  712.             iGameState=GS_STARTTURN;//set gamestate to start next turn
  713.         }break;
  714.     case GS_NULLMOVE://do not move the current unit
  715.         {
  716.             //don't really do anything, just go to the next unit
  717.             pCurrentUnit=NULL;
  718.             iGameState=GS_NEXTUNIT;
  719.         }break;
  720.     case GS_SKIPMOVE://skip this unit for now
  721.         {
  722.             //put unit at end of team unit list
  723.             TeamUnitList.push_back(pCurrentUnit);
  724.             pCurrentUnit=NULL;//set current unit to NULL
  725.             iGameState=GS_NEXTUNIT;//select the next unit
  726.         }break;
  727.     case GS_STARTMOVE:
  728.         {
  729.             //remove the unit from the map location
  730.             mlMap[pCurrentUnit->ptPosition.x][pCurrentUnit->ptPosition.y].ulUnitList.remove(pCurrentUnit);
  731.             Renderer.AddTile(pCurrentUnit->ptPosition.x,pCurrentUnit->ptPosition.y);
  732.             //set next gamestate
  733.             iGameState=GS_DOMOVE;
  734.         }break;
  735.     case GS_DOMOVE:
  736.         {
  737.             //move the unit
  738.             pCurrentUnit->ptPosition=TileWalker.TileWalk(pCurrentUnit->ptPosition,idMoveUnit);
  739.             //set next gamestate
  740.             iGameState=GS_ENDMOVE;
  741.         }break;
  742.     case GS_ENDMOVE:
  743.         {
  744.             //place the unit on its new map location
  745.             mlMap[pCurrentUnit->ptPosition.x][pCurrentUnit->ptPosition.y].ulUnitList.push_front(pCurrentUnit);
  746.             Renderer.AddTile(pCurrentUnit->ptPosition.x,pCurrentUnit->ptPosition.y);
  747.             pCurrentUnit=NULL;
  748.             bFlash=true;
  749.             //set next gamestate
  750.             iGameState=GS_NEXTUNIT;
  751.             DWORD dwTimeStart=GetTickCount();//get the frame start time
  752.             //scroll the frame (0,0)
  753.             Renderer.ScrollFrame(0,0);
  754.             //update the frame
  755.             Renderer.UpdateFrame();
  756.             //flip to show the back buffer
  757.             lpddsMain->Flip(0,DDFLIP_WAIT);
  758.             //wait until 500 ms have passed
  759.             while(GetTickCount()-dwTimeStart<500);
  760.         }break;
  761.     case GS_IDLE://the game is idling, update the frame, but thats about it.
  762.         {
  763.             DWORD dwTimeStart=GetTickCount();//get the frame start time
  764.             //scroll the frame (0,0)
  765.             Renderer.ScrollFrame(0,0);
  766.             //toggle unit flash
  767.             bFlash=!bFlash;
  768.             //add the tile in which the current unit lives
  769.             Renderer.AddTile(pCurrentUnit->ptPosition.x,pCurrentUnit->ptPosition.y);
  770.             //update the frame
  771.             Renderer.UpdateFrame();
  772.             //flip to show the back buffer
  773.             lpddsMain->Flip(0,DDFLIP_WAIT);
  774.             //wait until 200 ms have passed
  775.             while(GetTickCount()-dwTimeStart<200);
  776.         }break;
  777.     }
  778. }
  779.  
  780. void RenderFunc(LPDIRECTDRAWSURFACE7 lpddsDst,RECT* rcClip,int xDst,int yDst,int xMap,int yMap)
  781. {
  782.     //put background tile
  783.     tsBack.ClipTile(lpddsDst,rcClip,xDst,yDst,0);
  784.     //check for an empty list
  785.     if(!mlMap[xMap][yMap].ulUnitList.empty())
  786.     {
  787.         //list is not empty
  788.         UNITLISTITER iter=mlMap[xMap][yMap].ulUnitList.begin();//get iterator to beginning of list
  789.         PUNITINFO pUnitInfo=*iter;//grab the item
  790.         //if this is the current unit
  791.         if(pUnitInfo==pCurrentUnit)
  792.         {
  793.             //this is the current unit
  794.             if(!bFlash) return;//if flash is "off" dont render
  795.         }
  796.         tsUnit.ClipTile(lpddsDst,rcClip,xDst,yDst,pUnitInfo->iType);//place the unit
  797.         iter++;//move to the next item in the list
  798.         if(iter==mlMap[xMap][yMap].ulUnitList.end())//if the end of the list, this is a single unit
  799.         {
  800.             tsShield.ClipTile(lpddsDst,rcClip,xDst+ptShieldOffset[pUnitInfo->iType].x,yDst+ptShieldOffset[pUnitInfo->iType].y,pUnitInfo->iTeam*2);//place the shield
  801.         }
  802.         else//more than one unit... this is a stack
  803.         {
  804.             tsShield.ClipTile(lpddsDst,rcClip,xDst+ptShieldOffset[pUnitInfo->iType].x,yDst+ptShieldOffset[pUnitInfo->iType].y,pUnitInfo->iTeam*2+1);//place the shield
  805.         }
  806.     }
  807. }
  808.